#include "epollevent.hpp"


namespace libco {

EpollManager::EpollManager() {
    m_epfd = epoll_create1(EPOLL_CLOEXEC);
    LIBCO_ASSERT(m_epfd > 0);
}

EpollManager::~EpollManager() {
    close(m_epfd);
}

void EpollManager::add_event(int fd, EpollEvent events, std::function<void()> cb){
    FdContext* ctx = new FdContext();
    ctx->fd = fd;
    ctx->events = events;
    ctx->proc_id = t_id;

    epoll_event ev;
    ev.data.fd = fd;
    ev.events = EPOLLET | EPOLLRDHUP;
    if (events & EpollEvent::READ) {
        ev.events |= EPOLLIN;
        ctx->read_cb = cb;
    } else if (events & EpollEvent::WRITE) {
        ev.events |= EPOLLOUT;
        ctx->write_cb = cb;
    }


    Mutex::Lock lock(m_mutex);
    int op = m_fd_ctxs.find(fd) == m_fd_ctxs.end() ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;

    m_fd_ctxs[fd] = ctx;

    int rt = epoll_ctl(m_epfd, op, fd, &ev);
    LIBCO_ASSERT2(rt == 0, "epoll_ctl add or mod error");
}

void EpollManager::del_event(int fd) {
    Mutex::Lock lock(m_mutex);
    auto it = m_fd_ctxs.find(fd);
    if (it == m_fd_ctxs.end()) {
        return;
    }

    int rt = epoll_ctl(m_epfd, EPOLL_CTL_DEL, fd, nullptr);
    LIBCO_ASSERT2(rt == 0, "epoll_ctl del error");

    delete it->second;
    m_fd_ctxs.erase(it);
}

size_t EpollManager::GetPendingEvent() {
    return m_fd_ctxs.size();
}

} // namespace libco